from django.db import models
from django.db.models.fields import IntegerField
from django.utils.functional import curry
from django.utils.translation import ugettext_lazy as _

class OrderingField(IntegerField):
    empty_strings_allowed = False

    def __init__(self, with_respect_to=[], **kwargs):
        self.respect_to = with_respect_to
        kwargs['null'] = False
        kwargs['editable'] = False
        IntegerField.__init__(self, **kwargs )

    def get_internal_type(self):
        return 'IntegerField'

    def pre_save(self, model_instance, add):
        value = getattr(model_instance, self.attname)
        if value is None:
            value = model_instance._get_next_order_value()
            setattr(model_instance, self.attname, value)
        return super(OrderingField, self).pre_save(model_instance, add)
        
    def contribute_to_class(self, cls, name):
        assert not hasattr(cls._meta, 'has_ordering_field'), "A model can't have more than one OrderingField."
        super(OrderingField, self).contribute_to_class(cls, name)
        setattr(cls._meta, 'has_ordering_field', True)
        setattr(cls._meta, 'ordering_field', self)
        setattr(cls, 'move_up', curry(cls._move_up_or_down, is_up=True))
        setattr(cls, 'move_down', curry(cls._move_up_or_down, is_up=False))

class Model(object):
    def _get_next_order_value(self):
        field = getattr(self._meta, 'ordering_field')
        filter = dict((f.name, getattr(self, f.attname)) for f in field.respect_to)
        try:
            last = self.__class__._default_manager.filter(**filter).order_by('-%s' % field.name)[0]
            next = getattr(last, field.attname) + 1
        except IndexError:
            next = 1
        return next

    def _move_up_or_down(self, is_up=True):
        field = getattr(self._meta, 'ordering_field')
        filter = [(f.name, getattr(self, f.attname)) for f in field.respect_to]
        filter.append(('%s%s' % (field.name, is_up and '__lt' or '__gt'), getattr(self, field.attname)))
        order = '%s%s' % (is_up and '-' or '', field.name)
        try:
            a = self.__class__._default_manager.filter(**dict(filter)).order_by(order)[0]
        except IndexError:
            pass
        else:
            a.order, self.order = self.order, a.order
            a.save()
            self.save()
